#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/epoll.h>
#include <sys/socket.h>
#include <netdb.h>
#include <stdlib.h>
#include <errno.h>
#include <pthread.h>
#include <semaphore.h>
#include "thpool.h"
#include "reactor.h"
#include "server.h"
#include "acceptor.h"

int main(int argc,char *argv[]){
	thpool_t *thpool;
	reactor_t *reactor;
	int listenfd,epollfd;
	event_handler_t *eh;
	acceptor_t *acceptor;
	int ret;
	int i;

	thpool = thpool_init(THREAD_NUM);

	ret = server_init(&listenfd,&epollfd);
	reactor = create_reactor(epollfd,thpool);

	acceptor = create_acceptor(listenfd,reactor);
	reactor->acceptor = acceptor;

	reactor->event_loop(reactor);


	return 0;
}

int server_init(int *listenfd,int *epollfd){
	struct addrinfo hints;
	struct addrinfo *rp,*result;
	int optval,lfd,efd;

	memset(&hints,0,sizeof(struct addrinfo));
	hints.ai_socktype = SOCK_STREAM;
	hints.ai_family = AF_UNSPEC;
	hints.ai_flags = AI_PASSIVE | AI_NUMERICSERV;
	hints.ai_canonname = NULL;
	hints.ai_addr = NULL;
	hints.ai_next = NULL;

	if(getaddrinfo(NULL,PORT_NUM,&hints,&result) != 0){
		outputError(errno,"%s","getaddrinfo error");
	}

	optval = 1;
	for(rp = result; rp != NULL; rp = rp->ai_next){
		lfd = socket(rp->ai_family,rp->ai_socktype,rp->ai_protocol);
		if(lfd == -1){
			continue;
		}

		if(setsockopt(lfd,SOL_SOCKET,SO_REUSEADDR,&optval,sizeof(optval)) != 0){
			outputError(errno,"%s","setsockopt error");
		}

		if(bind(lfd,rp->ai_addr,rp->ai_addrlen) == 0){
			break;
		}

		close(lfd);
	}

	if(rp == NULL){
		outputError(errno,"%s","could not bind socket to any address");
	}

	if(listen(lfd,BACKLOG) == -1){
		outputError(errno,"%s","listen error");
	}

	*listenfd = lfd;

	efd = epoll_create(5);
	if(efd == -1){
		outputError(errno,"%s","epoll_create error");
	}

	*epollfd = efd;

	return 0;
}
